package anaydis.animation.sort.gui;

import anaydis.animation.sort.MergeSortAnimation;
import anaydis.animation.sort.SortAnimation;
import anaydis.sort.Sorter;
import anaydis.sort.SorterType;
import anaydis.sort.gui.ObservableSorter;
import anaydis.sort.provider.SorterProvider;
import com.sun.istack.internal.NotNull;

import javax.swing.*;
import java.awt.*;
import java.util.Vector;

public class Main
{
    private final JPanel mainPanel;
    private final SorterProvider provider;
    private final AnimationDisplayArea[] displayArea;

    public Main(@NotNull final SorterProvider provider, int panels)
    {
        this.provider = provider;
        displayArea = new AnimationDisplayArea[panels];
        JComboBox animations = createAlgorithmToAnimationAdapters();
        SortToolBar toolBar = new SortToolBar(animations);
        displayArea[0] = new AnimationDisplayArea(this, toolBar, animations, panels);

        //Create the main panel to contain the two sub panels.
        mainPanel = new JPanel();
        mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
        mainPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));

        //Add the select and display panels to the main panel.
        mainPanel.add(toolBar);
        mainPanel.add(Box.createRigidArea(new Dimension(0, 5)));
        mainPanel.add(displayArea[0]);

        if (panels == 2) {
            mainPanel.add(Box.createRigidArea(new Dimension(0, 5)));
            JPanel auxPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
            animations = createAlgorithmToAnimationAdapters();
            auxPanel.add(animations);
            mainPanel.add(auxPanel);
            mainPanel.add(Box.createRigidArea(new Dimension(0, 5)));
            displayArea[1] = new AnimationDisplayArea(this, toolBar, animations, panels);
            mainPanel.add(displayArea[1]);
        }
    }

    public void show()
    {
        //Create and set up the window.
        JFrame jframe = new JFrame("Sort");
        jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        jframe.setContentPane(mainPanel);

        //Display the window.
        jframe.pack();

        for (AnimationDisplayArea aDisplayArea : displayArea)
        {
            aDisplayArea.initAnimation();
        }

        jframe.setVisible(true);
    }

    private JComboBox createAlgorithmToAnimationAdapters()
    {
        final Vector<SortAnimation> vector = new Vector<SortAnimation>();

        for(Sorter sorter : provider.getAllSorters())
        {
            if (sorter instanceof ObservableSorter)
            {
                adaptSortAnimation(vector, sorter, (ObservableSorter) sorter);
            }
        }

        if(vector.isEmpty()) {
            errorMessage();
        }

        JComboBox sortChoices = new JComboBox(vector);
        sortChoices.setMaximumRowCount(vector.size());
        sortChoices.setMaximumSize(sortChoices.getPreferredSize());
        return sortChoices;
    }

    private void adaptSortAnimation(Vector<SortAnimation> vector, Sorter sorter, ObservableSorter observable)
    {
        final SortAnimation animation;

        if (sorter.getType() == SorterType.MERGE || sorter.getType() == SorterType.MERGE_BOTTOM_UP)
        {
            animation = new MergeSortAnimation(sorter);
        } else {
            animation = new SortAnimation(sorter);
        }

        observable.addSorterListener(animation);

        vector.add(animation);
    }

    public static void animate(@NotNull final SorterProvider provider)
    {
         SwingUtilities.invokeLater(new Runnable()
        {
            public void run()
            {
                final Main main = new Main(provider, 1);

                main.show();
            }
        });
    }

    public static void race(@NotNull final SorterProvider provider)
    {
         SwingUtilities.invokeLater(new Runnable()
        {
            public void run()
            {
                final Main main = new Main(provider, 2);

                main.show();
            }
        });
    }

    public boolean anyRunning()
    {
        for (AnimationDisplayArea aDisplayArea : displayArea) {
            if (aDisplayArea.isRunning())
                return true;
        }

        return false;
    }

    private void errorMessage()
    {
        JOptionPane.showMessageDialog(null, "Ooooooooops! SorterProvider contains no valid sorters! \n" +
                "Maybe you forgot adding your listeners to the provider,\n" +
                "or your listeners do not implement ObservableSorter!",
                "Anaydis Cannot Animate!", JOptionPane.ERROR_MESSAGE);

        System.exit(1);
    }
}